package com.jrx.anytxn.customer.Aspect;


import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.common.uitl.JsonUtils;
import com.jrx.anytxn.customer.entity.CmCustomerBankcardInfo;
import com.jrx.anytxn.customer.entity.CmCustomerFirstLevel;
import com.jrx.anytxn.customer.entity.CmCustomerMaintenanceLog;
import com.jrx.anytxn.customer.entity.CmCustomerSecondLevel;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerBankcardInfoMapper;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerFirstLevelMapper;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerMaintenanceLogMapper;
import com.jrx.anytxn.customer.mapper.ext.ExtCmCustomerSecondLevelMapper;
import com.jrx.anytxn.customer.plugins.HistoryLog;
import com.jrx.anytxn.customer.plugins.HistoryLogHelper;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import org.apache.commons.collections.CollectionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.*;

/**
 * 切面客户信息维护
 */

@Component
@Aspect
public class CustomerMaintenanceAspect {

    private static Logger logger = LoggerFactory.getLogger(CustomerMaintenanceAspect.class);

    @Resource
    private ExtCmCustomerBankcardInfoMapper extCmCustomerBankcardInfoMapper;
    @Resource
    private ExtCmCustomerSecondLevelMapper extCmCustomerSecondLevelMapper;
    @Resource
    private ExtCmCustomerMaintenanceLogMapper extCmCustomerMaintenanceLogMapper;
    @Resource
    private ExtCmCustomerFirstLevelMapper extCmCustomerFirstLevelMapper;
    @Autowired
    private ISegmentService iSegmentService;


    @Around("@annotation(com.jrx.anytxn.common.annotation.EnableHistoryLogAnnotation)")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取类名
        String methodName = pjp.getSignature().getDeclaringType().getSimpleName();
        Object[] args = pjp.getArgs();
        String req = JsonUtils.obj2json(args[0]);
        logger.info("[{}}类执行开始，请求报文[{}]",methodName,req);

        //记录历史
        saveCustomerMaintenance(pjp);


        //执行SQL并获取返回
        Object result = pjp.proceed();
        String returnStr = JsonUtils.obj2json(result);
        logger.info("[{}}类执行结束，返回报文[{}]",methodName,returnStr);
        return result;
    }

    private void saveCustomerMaintenance(ProceedingJoinPoint pjp) throws Throwable {
        //获取历史信息对象
        HistoryLog txnHistoryLog= HistoryLogHelper.getLocalHistory();
        //不存在则不进行处理
        if(null == txnHistoryLog){
            return ;
        }

        String methodName = pjp.getSignature().getDeclaringType().getSimpleName();

        HistoryLog log = new HistoryLog();

        String tableName = "";
        //获取所有属性
        Object[] args = pjp.getArgs();

        List<CmCustomerMaintenanceLog> customerMaintenanceLogs = new ArrayList<>();

        if ("ExtCmCustomerBankcardInfoMapper".equals(methodName)){
            tableName = "cm_customer_bankcard_info";
            CmCustomerBankcardInfo updateBankcardInfo = (CmCustomerBankcardInfo)args[0];
            CmCustomerBankcardInfo bankInfo = extCmCustomerBankcardInfoMapper.selectByIdAndCustomerId(
                    updateBankcardInfo.getId(),updateBankcardInfo.getTenantId(),updateBankcardInfo.getCustomerId());

            customerMaintenanceLogs =getCmCustomerMaintenanceLog(txnHistoryLog
                    ,bankInfo,updateBankcardInfo,tableName,updateBankcardInfo.getId());

        } else if ("ExtCmCustomerSecondLevelMapper".equals(methodName)){
            tableName = "cm_customer_second_level";
            CmCustomerSecondLevel updateSecondLevel = (CmCustomerSecondLevel)args[0];
            CmCustomerSecondLevel secondLevel = extCmCustomerSecondLevelMapper.selectByIdAndCustomerId(
                    updateSecondLevel.getId(),updateSecondLevel.getTenantId(),updateSecondLevel.getCustomerId());

            customerMaintenanceLogs =getCmCustomerMaintenanceLog(txnHistoryLog
                    ,secondLevel,updateSecondLevel,tableName,updateSecondLevel.getId());

        } else if ("ExtCmCustomerFirstLevelMapper".equals(methodName)){
            tableName = "cm_customer_first_level";
            CmCustomerFirstLevel updateDate = (CmCustomerFirstLevel)args[0];
            CmCustomerFirstLevel firstLevel = extCmCustomerFirstLevelMapper.selectByIdAndCustomerId(
                    updateDate.getId(),updateDate.getTenantId(),updateDate.getCustomerId());

            customerMaintenanceLogs =getCmCustomerMaintenanceLog(txnHistoryLog
                    ,firstLevel,updateDate,tableName,updateDate.getId());

        }
        if(CollectionUtils.isNotEmpty(customerMaintenanceLogs)){
            extCmCustomerMaintenanceLogMapper.batchInsertSelective(customerMaintenanceLogs);
        }
    }


    /*
     * 构建日志对象list
     */
    private List<CmCustomerMaintenanceLog> getCmCustomerMaintenanceLog(HistoryLog txnHistoryLog, Object oldResults
            , Object newResults, String tableName,Long id) throws SegmentException {
        List<CmCustomerMaintenanceLog> customerMaintenanceLogs = new ArrayList<>();

        Map<String, Map<String,Object>> resultMap = compareFields(oldResults,newResults);
        int size=resultMap.size();
        if(size>0) {
            Iterator<String> it = resultMap.keySet().iterator();
            while(it.hasNext()) {
                String key=it.next();
                logger.info("差异返回值：key ==>"+key+"(oldValue:"+resultMap.get(key).get("oldValue")+",newValue:"+resultMap.get(key).get("newValue")+")");
                if("id".equalsIgnoreCase(key)){
                    continue;
                }
                CmCustomerMaintenanceLog customerMaintenanceLog =new CmCustomerMaintenanceLog();
                customerMaintenanceLog.setId(iSegmentService.getId("CmCustomerMaintenanceLog"));
                customerMaintenanceLog.setChannel(txnHistoryLog.getChannel());
                customerMaintenanceLog.setCustomerId(txnHistoryLog.getCustomerId());
                customerMaintenanceLog.setTenantId(txnHistoryLog.getTenantId());
                customerMaintenanceLog.setOrganizationId(txnHistoryLog.getOrganizationId());
                customerMaintenanceLog.setUserId(txnHistoryLog.getUserId());
                customerMaintenanceLog.setModifyTableName(tableName);
                customerMaintenanceLog.setRecordId(id);
                customerMaintenanceLog.setFieldName(key);
                customerMaintenanceLog.setFieldValueOld(resultMap.get(key).get("oldValue")+"");
                customerMaintenanceLog.setFieldValueNew(resultMap.get(key).get("newValue")+"");
                customerMaintenanceLog.setLogType(txnHistoryLog.getType());
                customerMaintenanceLog.setRecordVersionNumber(1);
                customerMaintenanceLog.setUpdateBy(txnHistoryLog.getUserId());
                customerMaintenanceLog.setAlterReason(txnHistoryLog.getAlterReason());
                customerMaintenanceLogs.add(customerMaintenanceLog);
            }
        }
        return customerMaintenanceLogs;
    }

    private Map<String, Map<String,Object>> compareFields(Object oldObject, Object newObject) {
        Map<String, Map<String, Object>> map = null;
        try{
            if (oldObject.getClass() == newObject.getClass()) {
                map = new HashMap<String, Map<String,Object>>();

                Class clazz = oldObject.getClass();

                PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz,Object.class).getPropertyDescriptors();

                for (PropertyDescriptor pd : pds) {
                    String name = pd.getName();

                    Method readMethod = pd.getReadMethod();

                    Object oldValue = readMethod.invoke(oldObject);

                    Object newValue = readMethod.invoke(newObject);

                    if(oldValue instanceof List){
                        continue;
                    }

                    if(newValue instanceof List){
                        continue;
                    }

                    if(oldValue instanceof Timestamp){
                        oldValue = new Date(((Timestamp) oldValue).getTime());
                    }

                    if(newValue instanceof Timestamp){
                        newValue = new Date(((Timestamp) newValue).getTime());
                    }

                    if(oldValue instanceof Date){
                        oldValue = DateUtils.formatDateTime((Date) oldValue);
                    }

                    if(newValue instanceof Date){
                        newValue = DateUtils.formatDateTime((Date) newValue);
                    }

                    if(newValue == null){
                        continue;
                    }

                    if(oldValue == null && newValue == null){
                        continue;
                    }else if(oldValue == null && newValue != null){
                        Map<String,Object> valueMap = new HashMap<String,Object>();
                        valueMap.put("oldValue",oldValue);
                        valueMap.put("newValue",newValue);

                        map.put(name, valueMap);

                        continue;
                    }
                    if (!oldValue.equals(newValue)) {
                        Map<String,Object> valueMap = new HashMap<String,Object>();
                        valueMap.put("oldValue",oldValue);
                        valueMap.put("newValue",newValue);
                        map.put(name, valueMap);
                    }
                }
            }
        }catch(Exception e){
            logger.error("新旧数据对比异常:",e);
        }
        return map;
    }
}
